/*
 * XTableTest.java
 * 
 * Copyright (c) 2006 - 2007
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.xfc.table;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.io.DataInputStream;
import java.io.IOException;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;

import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.BorderFactory;
import javax.swing.Icon;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTabbedPane;
import javax.swing.JTable;
import javax.swing.UIManager;
import javax.swing.border.BevelBorder;
import javax.swing.border.Border;
import javax.swing.table.DefaultTableCellRenderer;

import org.xfc.XApp;
import org.xfc.XAppFrame;
import org.xfc.xdemos.helloworld.XHelloWorld;

import ca.odell.glazedlists.BasicEventList;
import ca.odell.glazedlists.EventList;

/**
 * 
 * 
 * @author Devon Carew
 */
public class XTableTest
	extends XApp
{
	
    public XTableTest()
    {
        super("XTableTest");
    }
    
	public static void main(String[] args)
		throws IOException
	{
		// Create the singleton instance of the application.
		XHelloWorld app = new XHelloWorld();
		
		// Create the main application frame.
		XAppFrame frame = new XAppFrame(app);
		
		app.registerGlobalAction("file-exit-action", app.getApplicationExitAction());
		
		JPanel contentPanel = frame.getFrameContent();
		
		JTabbedPane tabbedPane = new JTabbedPane();
		
		tabbedPane.addTab("Simple", createTable(0));
		tabbedPane.addTab("iTunes", createTable(1));
		tabbedPane.addTab("UIDefaults", createTable(2));
		
		contentPanel.setLayout(new BorderLayout());
		contentPanel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
		contentPanel.add(tabbedPane, BorderLayout.CENTER);
		
		frame.setTitle("XTableTest");
		frame.setSize(600, 300);
		frame.setVisible(true);
	}
	
	private static XTable createTable(int tableType)
		throws IOException
	{
		XTable table = new XTable();
		
		if (tableType == 0)
		{
			table.addColumn(new XTableColumn("First Name", String.class, 90) {
				public Object getValue(Object rowObject) {
					return ((Person)rowObject).firstName;
				}
			});
			table.addColumn(new XTableColumn("Last Name", String.class, 90) {
				public Object getValue(Object rowObject) {
					return ((Person)rowObject).lastName;
				}
			});
			table.addColumn(new XDoubleColumn("Age") {
				public Object getValue(Object rowObject) {
					return new Double(((Person)rowObject).age);
				}
			});
			
			final EventList rowObjects = new BasicEventList();
			
			rowObjects.add(new Person("Joe", "Smith", 32));
			rowObjects.add(new Person("Tyson", "Smith", 1));
			rowObjects.add(new Person("Sam", "Johnson", 32));
			rowObjects.add(new Person("Patrick", "Smith", 31));
			rowObjects.add(new Person("Henry", "Smith", 32));
			
			table.setRowObjects(rowObjects);
		}
		else if (tableType == 1)
		{
			initTable(table, "library.txt");
			
			table.addSelectionAction(new AddAction(table));
			table.addSelectionAction(new RemoveAction(table));
		}
		else
		{
			initTableUIDefaults(table);
		}
		
		return table;
	}
	
	private static class RemoveAction
		extends AbstractAction
		implements XTableSelectionAction
	{
		private XTable table;
		
		RemoveAction(XTable table)
		{
			this.table = table;
			
			putValue(Action.SMALL_ICON, XApp.getApp().getResources().getIcon("/eclipse/misc/delete_obj.gif"));
			putValue(Action.SHORT_DESCRIPTION, "Remove selected rows");
		}
		
		public void selectionChanged(XTable table)
		{
			setEnabled(!table.getTable().getSelectionModel().isSelectionEmpty());
		}

		public void actionPerformed(ActionEvent event)
		{
			EventList list = table.getVisibleRowObjects();
			
			try
			{
				list.getReadWriteLock().writeLock().lock();
				
				int[] selectedRows = table.getTable().getSelectedRows();
				
				for (int i = selectedRows.length - 1; i >= 0 ; i--)
					list.remove(selectedRows[i]);
			}
			finally
			{
				list.getReadWriteLock().writeLock().unlock();
			}
			
			table.getTable().clearSelection();
		}
	}

	private static class AddAction
		extends AbstractAction
		implements XTableSelectionAction
	{
		private XTable table;
		
		AddAction(XTable table)
		{
			this.table = table;
			
			putValue(Action.SMALL_ICON, XApp.getApp().getResources().getIcon("/eclipse/org.eclipse.ui/icons/full/obj16/add_obj.gif"));
			putValue(Action.SHORT_DESCRIPTION, "Add new row");
		}
		
		public void selectionChanged(XTable table)
		{
			// Not selection dependent -
			
		}
	
		public void actionPerformed(ActionEvent event)
		{
			EventList list = table.getVisibleRowObjects();
			
			try
			{
				list.getReadWriteLock().writeLock().lock();
				
				int index = table.getTable().getSelectedRow();
				
				Object rowObject = new HashMap();
				
				if (index == -1)
				{
					list.add(rowObject);
					index = list.size() - 1;
				}
				else
				{
					list.add(index, rowObject);
				}
				
				table.getTable().getSelectionModel().setSelectionInterval(index, index);
				table.getTable().scrollRectToVisible(table.getTable().getCellRect(index, 0, true));
			}
			finally
			{
				list.getReadWriteLock().writeLock().unlock();
			}
		}
	}
	
	static class Person
	{
		public String firstName;
		public String lastName;
		public int age;
		
		public Person(String firstName, String lastName, int age)
		{
			this.firstName = firstName;
			this.lastName = lastName;
			this.age = age;
		}
	}
	
	private static void initTable(XTable table, String resName)
		throws IOException
	{
		DataInputStream in = new DataInputStream(XTableTest.class.getResourceAsStream(resName));
		
		String temp = in.readLine();
		
		String[] headers = temp.split("\t");
		
		for (int i = 0; i < headers.length; i++)
		{
			table.addColumn(new XTableColumn(headers[i], String.class) {
				public Object getValue(Object rowObject) {
					Map map = (Map)rowObject;
					return map == null ? null : map.get(getHeaderValue());
				}
			});
		}
		
		EventList list = new BasicEventList();
		
		String line = in.readLine();
		
		while (line != null)
		{
			line = line.trim();
			
			if (line.length() > 0)
			{
				String[] data = line.split("\t");
				
				Map map = new HashMap();
				
				for (int i = 0; i < data.length; i++)
					map.put(headers[i], data[i]);
				
				list.add(map);
			}
			
			line = in.readLine();
		}
		
		table.getRowHeader().setDefaultRenderer(new XRowHeaderRenderer(true));
		
		table.setRowObjects(list);
	}
	
	private static void initTableUIDefaults(XTable table)
	{
		table.addColumn(new XTableColumn("Key Name", String.class, 250) {
			public Object getValue(Object rowObject) {
				return rowObject;
			}
		});
		table.addColumn(new XTableColumn("Rendering", Object.class, 90) {
			{ setCellRenderer(new FlexibleRenderer()); }
			public Object getValue(Object rowObject) {
				Icon icon = UIManager.getIcon(rowObject);
				
				if (icon != null)
					return icon;
				
				Color color = UIManager.getColor(rowObject);
				
				if (color != null)
					return color;
				
				Font font = UIManager.getFont(rowObject);
				
				if (font != null)
					return font;
				
				return null;
			}
		});
		table.addColumn(new XTableColumn("UIManager Value", String.class, 375) {
			public Object getValue(Object rowObject) {
				Object result = UIManager.get(rowObject);
				
				if (result instanceof String)
					return result;
				
				return result == null ? null : result.toString();
			}
		});
		
		EventList list = new BasicEventList();
		
		for (Enumeration e = UIManager.getDefaults().keys(); e.hasMoreElements(); )
		{
			Object object = e.nextElement();
			
			if (object instanceof String)
				list.add(object);
		}
		
		table.setRowObjects(list);
	}
	
	static class FlexibleRenderer
		extends DefaultTableCellRenderer
	{
		Color 	defaultBackground;
		Border	loweredBorder;
		Font	defaultFont;
		
		public FlexibleRenderer()
		{
			defaultBackground = getBackground();
			defaultFont = getFont();
			
			setHorizontalAlignment(JLabel.RIGHT);

			Color controlLight = UIManager.getColor("controlLtHighlight");
			Color controlDark = UIManager.getColor("controlDkShadow");

			loweredBorder = BorderFactory.createBevelBorder(BevelBorder.LOWERED, controlLight, controlDark);
		}
		
		public Component getTableCellRendererComponent(JTable table, Object value, boolean selected, boolean focused, int row, int column)
		{
			setIcon(null);
			setText(null);
			setBackground(defaultBackground);
			setBorder(null);
			setFont(defaultFont);
			
			super.getTableCellRendererComponent(table, "", selected, focused, row, column);
			
			if (value instanceof Icon)
			{
				setIcon((Icon)value);
			}
			else if (value instanceof Color)
			{
				setBackground((Color)value);
				setBorder(loweredBorder);
			}
			else if (value instanceof Font)
			{
				setText("Ran run dog");
				setFont((Font)value);
			}
			
			return this;
		}

		public void paint(Graphics g)
		{
			try
			{
				super.paint(g);
			}
			catch (ClassCastException cce)
			{
				// Some of the icons expect to be in a certain componet heirarchy when they're rendered.
			}
		}
	}
	
}
